package xyz.zhouxf.rpc.transport.netty.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import xyz.zhouxf.rpc.codec.CommonDecoder;
import xyz.zhouxf.rpc.codec.CommonEncoder;
import xyz.zhouxf.rpc.serializer.RpcSerializer;
import xyz.zhouxf.rpc.serializer.impl.JsonSerializer;


import java.net.InetSocketAddress;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author zhouxf
 * @date 2022/10/5
 */
public class ChannelManager {

    private static Map<String, Channel> channels = new ConcurrentHashMap<>();

    private static EventLoopGroup eventLoopGroup;

    private static Bootstrap bootstrap = initBootStrap();

    public static Channel getChannel(InetSocketAddress inetSocketAddress, RpcSerializer serializer) {
        String key = inetSocketAddress.toString() + serializer.getCode();
        if(channels.containsKey(key)) {
            Channel channel = channels.get(key);
            if(channel != null && channel.isActive()) {
                return channel;
            }else {
                channels.remove(key);
            }
        }
        bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
            @Override
            protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
                ChannelPipeline pipeline = nioSocketChannel.pipeline();
                pipeline.addLast(new CommonDecoder());
                pipeline.addLast(new CommonEncoder(serializer));
                pipeline.addLast(new NettyClientHandler());
            }
        });
        Channel channel = null;
        try {
            channel = bootstrap.connect(inetSocketAddress).sync().channel();
            channel.closeFuture().addListener(future -> {
                eventLoopGroup.shutdownGracefully();
            });
        } catch (InterruptedException e) {
            e.printStackTrace();
            return null;
        }
        return channel;
    }

    public static Bootstrap initBootStrap() {
        eventLoopGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(eventLoopGroup)
                .channel(NioSocketChannel.class);
        return bootstrap;
    }

}
